<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>JS中的event delegate，什么是event delegate（事件委托）</title>

    <link rel="stylesheet" href="../css/reveal/reveal.css">

    <!-- PPT主题，可以在/css/reveal/theme/中选择其他主题，目前暂时只能使用该模板 -->
    <link rel="stylesheet" href="../css/reveal/theme/ptt.css">

    <!-- syntax highlighting 代码高亮主题 -->
    <link rel="stylesheet" href="../lib/reveal/css/zenburn.css">

    <!-- 打印和PDF输出样式 -->
    <script>
        var link = document.createElement( 'link' );
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = window.location.search.match( /print-pdf/gi ) ? '../css/reveal/print/pdf.css' : '../css/reveal/print/paper.css';
        document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>
</head>
<body>
<img src="../img/demo/logo.png" alt="" usemap="#pttmap" class="base-logo">
<map name="pttmap">
    <area shape="rect" coords="0,0,276,58" href="http://www.jnshu.com" alt="" target="_blank"/>
</map>
<div class="reveal">
    <div class="slides">
        <section>
            <h2>【js-04】JS中的event delegate，什么是event delegate（事件委托）?</h2>

            <h3>小课堂【成都分院】</h3>

            <p style="text-align: center;">分享人：文世豪</p>
        </section>
        <section>
            <p>目录</p>
            <p>1.背景介绍</p>
            <p>2.知识剖析</p>
            <p>3.常见问题</p>
            <p>4.解决方案</p>
            <p>5.编码实战</p>
            <p>6.扩展思考</p>
            <p>7.参考文献</p>
            <p>8.更多讨论</p>
        </section>
        <section>
            <h3>1.背景介绍</h3>
        </section>
        <section>
            <p>事件处理程序可以为现代web应用程序提供交互能力，因此许多开发人员会向页面中添加大量的处理程序。
                但是在JavaScript中，添加到页面中的事件处理程序的数量会直接影响页面的整体运行性能。
                理由：1.每个函数都是对象，都会占用内存。
                2.事先指定所有的事件处理程序会导致DOM的访问次数增加，会延迟整个页面的交互时间。 对“事件处理程序过多”问题的解决方案就是事件委托（Delegation）。

            </p>
        </section>
        <section>
            <h3>2.知识剖析</h3>
        </section>
        <section>
            <section>
                2.1为什么要用事件委托
                在JavaScript中，添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能， 因为需要不断的与dom节点进行交互，访问dom的次数越多，引起浏览器重绘与重排的次数也就越多， 就会延长整个页面的交互就绪时间，这就是为什么性能优化的主要思想之一就是减少DOM操作的原因；
                每个函数都是一个对象，是对象就会占用内存，对象越多，内存占用率越大，100个li就要占用100个内存空间。 如果要用事件委托，就会将所有的操作放到js程序里面，只对它的父级(如果只有一个父级)这一个对象进行操作， 与dom的操作就只需要交互一次，这样就能大大的减少与dom的交互次数，提高性能；

            </section>
            <section>
                <p>事件委托的原理</p>
                <p>事件委托是利用事件的冒泡原理来实现的，何为事件冒泡呢？
                    就是事件从最深的节点开始，然后逐步向上传播事件，
                    举个例子：
                    页面上有这么一个节点树，div>ul>li>a;比如给最里面的a加一个click点击事件， 那么这个事件就会一层一层的往外执行，执行顺序a>li>ul>div， 有这样一个机制，那么我们给最外面的div加点击事件，那么里面的ul，li，a做点击事件的时候， 都会冒泡到最外层的div上，所以都会触发，这就是事件委托，委托它们父级代为执行事件。
                    </p>
            </section>
            <section>
                <p style="text-align: left">子节点实现功能的例子：</p>
                 <pre>
            <code>
                <ul id="ull">
                    <li>1</li>
                    <li>2</li>
                    <li>3</li>
                </ul>
                <script>
                    window.onload=function () {
                        var oul=document.getElementById('ull');
                        var ali=oul.getElementsByTagName('li');
                        for(var i=0;i<ali.length;i++){
                            ali[i].onclick=function () {
                                alert(123);
                                
                            }
                        }

                    }
                </script>
            </code>
            </pre>
                <p>我们看看有多少次的dom操作，首先要找到ul，然后遍历li，然后点击li的时候，又要找一次目标的li的位置，才能执行最后的操作，每次点击都要找一次li；</p>
            </section>
            <section>
                <p style="text-align: left">委托的方式做又如何呢：</p>
                <pre>
                    <code>
                        <script>
                            window.onload=function () {
                                var oul=document.getElementById('ull');
                                oul.onclick=function () {
                                    alert(123);
                                }
                            }
                        </script>
                    </code>
                </pre>
                <p>这里用父级ul做事件处理，当li被点击时，由于冒泡原理，事件就会冒泡到ul上，因为ul上有点击事件，所以事件就会触发，当然，这里当点击ul的时候，也是会触发的.</p>
            </section>
        </section>
        <section>
            <h3>3.事件冒泡及捕获</h3>
        </section>
        <section>

            <p>
                DOM2.0模型将事件处理流程分为三个阶段：
                一、事件捕获阶段，
                二、事件目标阶段，
                三、事件起泡阶段。
            </p>
        </section>
        <section>
            <p>事件捕获：
                当某个元素触发某个事件（如onclick），顶层对象document就会发出一个事件流，
                随着DOM树的节点向目标元素节点流去，直到到达事件真正发生的目标元素。
                在这个过程中，事件相应的监听函数是不会被触发的。</p>
        </section>
        <section>
            <p>
                事件目标：
                当到达目标元素之后，执行目标元素该事件相应的处理函数。如果没有绑定监听函数，那就不执行。
            </p>
        </section>
        <section>
            <p>
                事件起泡：
                从目标元素开始，往顶层元素传播。途中如果有节点绑定了相应的事件处理函数，这些函数都会被触发
            </p>
        </section>
        <section>
            <p>
                2.4事件委托的优点
                通过刚才的对比介绍，大家应该能够体会到使用事件委托对于web应用程序带来的几个优点：
                1.管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素，可以通过委托给父元素的监听函数来处理事件。
                2.可以方便地动态添加和修改元素，不需要因为元素的改动而修改事件绑定。
                3.JavaScript和DOM节点之间的关联变少了，这样也就减少了因循环引用而带来的内存泄漏发生的概率。

            </p>
        </section>
        <section>
            <h3>4.常见问题</h3>
            <p>如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办?
                比如说只有点击li才会触发?</p>
        </section>
        <section>
            <p>
                Event对象提供了一个属性叫target，可以返回事件的目标节点，
                我们成为事件源， 也就是说，target就可以表示为当前的事件操作的dom，但是不是真正操作dom。
                标准浏览器用ev.target，IE浏览器用event.srcElement，此时只是获取了当前节点的位置， 并不知道是什么节点名称，这里我们用nodeName来获取具体是什么标签名。
                这样改下就只有点击li会触发事件了，且每次只执行一次dom操作

            </p>
        </section>
        <section>
            <h3>5.编码实战</h3>
        </section>
        <section>
            <h3>6.扩展思考</h3>
        </section>
        <section>
            <p>事件对象的公共成员：
                对比currentTarget和target
            </p>
        </section>
        <section>
            <h3>7.参考文献</h3>
        </section>
        <section>
            <h4>感谢观看</h4>
            <p><small>BY : 文世豪 </small></p>
        </section>
    </div>
</div>

<script src="../lib/reveal/js/head.min.js"></script>
<script src="../lib/reveal/reveal.js"></script>

<script>

    // 以下为常见配置属性的默认值
    // {
    // 	controls: true, // 是否在右下角展示控制条
    // 	progress: true, // 是否显示演示的进度条
    // 	slideNumber: false, // 是否显示当前幻灯片的页数编号，也可以使用代码slideNumber: 'c / t' ，表示当前页/总页数。
    // 	history: false, // 是否将每个幻灯片改变加入到浏览器的历史记录中去
    // 	keyboard: true, // 是否启用键盘快捷键来导航
    // 	overview: true, // 是否启用幻灯片的概览模式，可使用"Esc"或"o"键来切换概览模式
    // 	center: true, // 是否将幻灯片垂直居中
    // 	touch: true, // 是否在触屏设备上启用触
    Reveal.initialize({
        history: true,
        dependencies: [
            {src: '../plugin/markdown/marked.js'},
            {src: '../plugin/markdown/markdown.js'},
            {src: '../plugin/notes/notes.js', async: true},
            {
                src: '../plugin/highlight/highlight.js', async: true, callback: function () {
                hljs.initHighlightingOnLoad();
            }
            }
        ]
    });
</script>
</body>
</html>
